/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.acceptance.worker;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;
import org.ourgrid.acceptance.util.worker.Req_004_Util;
import org.ourgrid.acceptance.util.worker.Req_006_Util;
import org.ourgrid.acceptance.util.worker.Req_079_Util;
import org.ourgrid.acceptance.util.worker.Req_087_Util;
import org.ourgrid.acceptance.util.worker.Req_090_Util;
import org.ourgrid.acceptance.util.worker.Req_091_Util;
import org.ourgrid.acceptance.util.worker.Req_092_Util;
import org.ourgrid.acceptance.util.worker.Req_121_Util;
import org.ourgrid.common.interfaces.Worker;
import org.ourgrid.common.interfaces.management.RemoteWorkerManagement;
import org.ourgrid.common.interfaces.management.RemoteWorkerManagementClient;
import org.ourgrid.common.interfaces.management.WorkerManagementClient;
import org.ourgrid.common.interfaces.to.WorkerStatus;
import org.ourgrid.reqtrace.ReqTest;
import org.ourgrid.worker.WorkerComponent;
import org.ourgrid.worker.WorkerConstants;

import br.edu.ufcg.lsd.commune.identification.ContainerID;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;

@ReqTest(reqs="REQ091")
public class Req_091_Test extends WorkerAcceptanceTestCase {
	
	private DeploymentID peerID;
	private Req_004_Util req_004_Util = new Req_004_Util(getComponentContext());
	private Req_090_Util req_090_Util = new Req_090_Util(getComponentContext());
	private Req_092_Util req_092_Util = new Req_092_Util(getComponentContext());
	private Req_079_Util req_079_Util = new Req_079_Util(getComponentContext());
	private Req_006_Util req_006_Util = new Req_006_Util(getComponentContext());
	private Req_121_Util req_121_Util = new Req_121_Util(getComponentContext());
	private Req_091_Util req_091_Util = new Req_091_Util(getComponentContext());
	private Req_087_Util req_087_Util = new Req_087_Util(getComponentContext());
	
	@Before
	public void setUp() throws Exception {
		super.setUp();
		String peerPubKey = workerAcceptanceUtil.simulateAuthentication();
		
		peerID = new DeploymentID(new ContainerID("peerUser", "peerServer", "peerModule", peerPubKey), "peerObj");
	}
	
	/**
	 * This tests contains the following steps:
	 * 
	 *    1. Start a Worker with the master peer public key property: "publicKey1" and with the idleness detector disabled;
	 *    2. A peer with the public key "publicKey222" sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to stop working. This message was ignored. Unknown peer public key: [unknownPublicKey]."
	 *    3. A peer with the public key "publicKey1" sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    4. A peer with the public key "publicKey222" sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to stop working. This message was ignored. Unknown peer public key: [unknownPublicKey]."
	 * 
	 */
	@ReqTest(test=" AT-091.1", reqs="REQ091")
	@Test public void test_at_091_1_UnknownPeerRequestsWorkerToStopWorking() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Unknown peer [publicKey222] sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingByUnknownPeer(component, "publicKey222");
		
		// Master peer sends a setPeer message - expect an info to be logged
		req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Unknown peer [publicKey222] sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingByUnknownPeer(component, "publicKey222");
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector disabled;
	 *    2. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "The master Peer tried to manage this Worker before setting itself as manager of this Worker. This message was ignored."
   	 *    3. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    4. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "This Worker was commanded to stop working, but it's not working for any client. This message was ignored."
	 *    5. Pause the Worker;
	 *           * Verify if the following info message was logged: "Worker has been PAUSED."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to OWNER."
	 *           * Expect the Worker to send the peer a status changed message, with the OWNER status
	 *    6. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "This Worker was commanded to stop working, but it's not working for any client. This message was ignored."
	 * 
	 */
	@ReqTest(test=" AT-091.2", reqs="REQ091")
	@Test public void test_at_091_2_WorkerWhichIsNotWorkingIsAssignedToStopWorking() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingByUnsetMasterPeer(component, peerID.getPublicKey());
		
		// Master peer sends a setPeer message - expect an info to be logged
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Master peer sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingWithoutBeingWorking(component, peerID.getPublicKey());
		
		// Pause the worker
		req_087_Util.pauseIdleWorkerWithoutCleaning(component, wmc);
		
		// Master peer sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingWithoutBeingWorking(component, peerID.getPublicKey());
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. Verify if the WORKER object is bound
	 *    5. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following info message was logged: "This Worker was commanded to stop working for the current client."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to IDLE."
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    6. Verify if the WORKER object is NOT bound
	 *    7. The master peer commands the Worker to work for the client with the public key "mgPublicKey222";
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPublicKey222]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    8. A client with the public key "mgPublicKey222" sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID].
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    9. Verify if the WORKER object is bound
	 *   10. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following info message was logged: "This Worker was commanded to stop working for the current client."
	 *           * Verify if the following debug message was logged: "Cleaning Worker."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to IDLE."
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *   11. Verify if the WORKER object is NOT bound
	 *   12. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following warn message was logged: "This Worker was commanded to stop working, but it's not working for any client. This message was ignored."
	 * 
	 */
	@ReqTest(test=" AT-091.3", reqs="REQ091")
	@Test public void test_at_091_3_WorkerWorkingForLocalClientIsAssignedToStopWorking() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends a setPeer message - expect an info to be logged
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Master peer sends a workForMyGrid message - expect an info and a debug to be logged
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey");
		req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Verify if the Worker is bound
		assertTrue(workerAcceptanceUtil.isWorkerBound());
		
		// Master peer sends a stopWorking message - expect an info and a debug to be logged
		req_091_Util.stopWorkingOnAllocatedForMyGridWorker(component, wmc, peerID.getPublicKey());
		
		// Verify if the Worker is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Master peer sends a workForMyGrid message - expect an info and a debug to be logged
		String mgPubKey = "mgPubKey222";
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, mgPubKey);
		Worker worker2 = req_092_Util.beginAllocationCompleted(component, wmc);
		
		// Client [mgPubKey222] sends a startWork message - expect an info to be logged
		DeploymentID myGridID = new DeploymentID(new ContainerID("mgUser", "mgServer", "mgModule", mgPubKey), "mgObj");
		
		req_079_Util.startWorkSuccessfully(component, worker2, myGridID);
		
		// Verify if the Worker is bound
		assertTrue(isBound(component, WorkerConstants.WORKER, Worker.class));

		// Master peer sends a stopWorking message - expect an info and a debug to be logged
		req_091_Util.stopWorkingOnAllocatedForMyGridWorker(component, wmc, peerID.getPublicKey());

		// Verify if the Worker is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Master peer sends a stopWorking message - expect a warn to be logged
		req_091_Util.stopWorkingWithoutBeingWorking(component, peerID.getPublicKey());
	}

	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForPeer message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a remote peer. Remote peer public key: [peerPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_PEER."
	 *           * Expect the Worker to send the peer an allocated for peer status changed message, with a stub to the Remote Worker Management remote object
	 *    4. Verify if the REMOTE_WORKER_MANAGEMENT object is bound
	 *    5. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following info message was logged: "This Worker was commanded to stop working for the current client."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_PEER to IDLE."
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    6. Verify if the REMOTE_WORKER_MANAGEMENT object is NOT bound
	 *    7. The master peer sends a workForPeer message to the Worker, with another public key;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a remote peer. Remote peer public key: [peerPubKeyABC]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_PEER."
	 *           * Expect the Worker to send the peer an allocated for peer status changed message, with a stub to the Remote Worker Management remote object
	 *    8. The remote peer with the public key "peerPubKeyABC" commands the Worker to work for the remote client with the public key "mgPubKey";
	 *           * Verify if the following info message was logged: "Remote peer commanded this Worker to work for a remote consumer. Remote consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_PEER to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the remote peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    9. Verify if the WORKER object is bound
	 *   10. Verify if the REMOTE_WORKER_MANAGEMENT object is bound
	 *   11. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following info message was logged: "This Worker was commanded to stop working for the current client."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to IDLE."
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *   12. Verify if the WORKER object is NOT bound
	 *   13. Verify if the REMOTE_WORKER_MANAGEMENT object is NOT bound
	 * 
	 */
	@ReqTest(test=" AT-091.4", reqs="REQ091")
	@Test public void test_at_091_4_WorkerWorkingForRemotePeerIsAssignedToStopWorking1() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends a setPeer message - expect an info to be logged
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Master peer sends a workForPeer message - expect an info and a debug to be logged
		req_006_Util.workForPeerOnIdleWorker(component, wmc, peerID.getPublicKey(), "peerPubKey");
		
		// Verify if the RemoteWorkerManagement is bound
		assertTrue(isBound(component, WorkerConstants.REMOTE_WORKER_MANAGEMENT, 
				RemoteWorkerManagement.class));
		
		// Master peer sends a stopWorking message - expect an info and a debug to be logged
		req_091_Util.stopWorkingOnAllocatedForPeerWorker(component, wmc, peerID.getPublicKey());
		
		// Verify if the RemoteWorkerManagement is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Master peer sends a workForPeer message with another public key - expect an info and a debug to be logged
		String remPeerPubKey = "peerPubKeyABC";
		req_006_Util.workForPeerOnIdleWorker(component, wmc, peerID.getPublicKey(), remPeerPubKey);
		
		// Remote peer [peerPubKeyABC] commands the worker to work for a remote client [mgPubKey] - expect an info and a debug to be logged
		RemoteWorkerManagementClient rwmc = req_121_Util.workForMyGridOnAllocatedForPeerWorker(component, remPeerPubKey, "mgPubKey");
		req_121_Util.beginAllocationCompleted(component, rwmc);
		
		// Verify if the Worker is bound
		assertTrue(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Verify if the RemoteWorkerManagement is bound
		assertTrue(isBound(component, WorkerConstants.REMOTE_WORKER_MANAGEMENT, 
				RemoteWorkerManagement.class));
		
		// Master peer sends a stopWorking message - expect an info and a debug to be logged
		req_091_Util.stopWorkingOnAllocatedForMyGridWorker(component, wmc, peerID.getPublicKey());
		
		// Verify if the Worker is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Verify if the RemoteWorkerManagement is NOT bound
		assertFalse(isBound(component, WorkerConstants.REMOTE_WORKER_MANAGEMENT, 
				RemoteWorkerManagement.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForPeer message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a remote peer. Remote peer public key: [peerPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_PEER."
	 *           * Expect the Worker to send the peer an allocated for peer status changed message, with a stub to the Remote Worker Management remote object
	 *    4. The remote peer with the public key "peerPubKey" commands the Worker to work for the remote client with the public key "mgPubKey";
	 *           * Verify if the following info message was logged: "Remote peer commanded this Worker to work for a remote consumer. Remote consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_PEER to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the remote peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    5. A client with the public key "mgPubKey" sends a startWork message;
	 *           * Verify if the following info message was logged: Worker is ready to start working for client [ClientID].
	 *           * Expect the Worker to send the client a Worker is Ready message
	 *    6. Verify if the WORKER object is bound
	 *    7. Verify if the REMOTE_WORKER_MANAGEMENT object is bound
	 *    8. The master peer sends a stopWorking message to the Worker;
	 *           * Verify if the following info message was logged: "This Worker was commanded to stop working for the current client."
	 *           * Verify if the following debug message was logged: "Cleaning Worker."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to IDLE."
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    9. Verify if the WORKER object is NOT bound
	 *   10. Verify if the REMOTE_WORKER_MANAGEMENT object is NOT bound
	 * 
	 */
	@ReqTest(test=" AT-091.5", reqs="REQ091")
	@Test public void test_at_091_5_WorkerWorkingForRemoteClientIsAssignedToStopWorking2() throws Exception {
		// Start worker without idleness detector
		WorkerComponent component = req_004_Util.startWorker();
		
		// Master peer sends a setPeer message - expect an info to be logged
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		// Master peer sends a workForPeer message - expect an info and a debug to be logged
		String peerPubKey = "peerPubKey";
		req_006_Util.workForPeerOnIdleWorker(component, wmc, peerID.getPublicKey(), peerPubKey);
		
		// Remote peer [peerPubKey] commands the worker to work for a remote client [mgPubKey] - expect an info and a debug to be logged
		DeploymentID myGridID = new DeploymentID(new ContainerID("mgUser", "mgServer", "mgModule", "mgPubKey"), "mgObj");
		
		RemoteWorkerManagementClient rwmc = req_121_Util.workForMyGridOnAllocatedForPeerWorker(component, peerPubKey, myGridID.getPublicKey());
		Worker worker = req_121_Util.beginAllocationCompleted(component, rwmc);
		
		// Client [mgPubKey] sends a startWork - expect an info to be logged
		req_079_Util.startWorkSuccessfully(component, worker, myGridID);
		
		// Verify if the Worker is bound
		assertTrue(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Verify if the RemoteWorkerManagement is bound
		assertTrue(isBound(component, WorkerConstants.REMOTE_WORKER_MANAGEMENT, 
				RemoteWorkerManagement.class));
		
		// Master peer sends a stopWorking message - expect an info and two debugs to be logged
		req_091_Util.stopWorkingOnAllocatedForMyGridWorker(component, wmc, peerID.getPublicKey());
		
		// Verify if the Worker is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		// Verify if the RemoteWorkerManagement is NOT bound
		assertFalse(isBound(component, WorkerConstants.REMOTE_WORKER_MANAGEMENT, 
				RemoteWorkerManagement.class));
	}
	
}